use std::ffi::CString;
use std::ptr::{null, null_mut};
use winapi::shared::minwindef::{DWORD, HMODULE, BOOL};
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{STARTUPINFOA, PROCESS_INFORMATION, CreateProcessA};
use winapi::um::synchapi::WaitForSingleObject;
use winapi::um::winbase::{CREATE_NEW_CONSOLE, INFINITE};
use winapi::um::libloaderapi::{FreeLibraryAndExitThread, GetModuleHandleA};

#[unsafe(no_mangle)]
pub extern "stdcall" fn DllMain(
    h_module: HMODULE,
    dw_reason: DWORD,
    _lp_reserved: *mut std::ffi::c_void,
) -> BOOL {
    match dw_reason {
        1 => { 
            unsafe {
                let mut startup_info: STARTUPINFOA = std::mem::zeroed();
                startup_info.cb = std::mem::size_of::<STARTUPINFOA>() as u32;

                let mut process_info: PROCESS_INFORMATION = std::mem::zeroed();

                let application_name = match CString::new("C:\\Windows\\System32\\calc.exe") {
                    Ok(cstr) => cstr,
                    Err(_) => return 0, 
                };

                let success = CreateProcessA(
                    null(),
                    application_name.as_ptr() as *mut i8,
                    null_mut(),
                    null_mut(),
                    0, // FALSE
                    CREATE_NEW_CONSOLE,
                    null_mut(),
                    null(),
                    &mut startup_info,
                    &mut process_info,
                );

                if success == 0 {
                    return 0; 
                }

                std::thread::spawn(move || {
                    WaitForSingleObject(process_info.hProcess, INFINITE);
                    CloseHandle(process_info.hProcess);
                    CloseHandle(process_info.hThread);
                    FreeLibraryAndExitThread(h_module, 0);
                });

                1 
            }
        },
        0 => { // DLL_PROCESS_DETACH
            1 
        },
        _ => 1, // Return TRUE for other cases (DLL_THREAD_ATTACH, DLL_THREAD_DETACH)
    }
}